﻿using Marmat.Forms;
using System;
using System.Collections.Generic;
using System.Collections;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;

namespace Marmat.Template.WinForm
{
    /// <summary>
    /// 单据编辑窗体。
    /// </summary>
    /// <typeparam name="Entity"></typeparam>
    /// <typeparam name="Source"></typeparam>
    public partial class DocumentEditForm<Entity, Source> : System.Windows.Forms.Form, IDocumentEditForm<Entity, Source>, Marmat.Foundation.IEditFormEditorStyle
    {
        /// <summary>
        /// 构建单据编辑窗体的实例。
        /// </summary>
        public DocumentEditForm()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 获取或设置是否允许编辑
        /// </summary>
        public bool Editable { get => this.bGridControl1.Editable; set => this.bGridControl1.Editable = value; }

        /// <summary>
        /// 编辑控制器
        /// </summary>
        public IDocumentEditFormController<Entity, Source> Controller { get; set; }

        /// <summary>
        /// 数据源
        /// </summary>
        public Entity DataSource { get; set; }

        /// <summary>
        /// 列数量
        /// </summary>
        [System.ComponentModel.DefaultValue(3)]
        public int ColumnCount { get; protected set; } = 3;

        /// <summary>
        /// 窗体上的控件集合
        /// </summary>
        public Dictionary<string, System.Windows.Forms.Control> FIeldCollection { get; } = new Dictionary<string, Control>();

        /// <summary>
        /// 加载数据
        /// </summary>
        /// <param name="data"></param>
        void IDocumentEditForm<Entity, Source>.Load(Entity data)
        {
            this.DataSource = data;
            if (this.bGridControl1.Columns.Count == 0)
            {
                var editColumns = this.Controller.Management.GetColumnCollection();
                foreach (var item in editColumns)
                {
                    Forms.Views.Grid.Column column = new Forms.Views.Grid.Column
                    {
                        Name = item.Name,
                        Caption = item.Caption,
                        FieldName = item.Name
                    };
                    this.bGridControl1.Columns.Add(column);
                }
            }
            if (data is System.Data.DataRow row)
                this.bGridControl1.DataSource = row.Table;
            else
                this.bGridControl1.DataSource = data;
            this.Text = this.Controller.Management.Text;
        }

        private void UserEntityEditForm_Load(object sender, EventArgs e)
        {
            if (this.DesignMode) return;
            List<BuildControlArgs> buildControls = new List<BuildControlArgs>();
            IEnumerable<ColumnEntity> columnCollection = this.Controller.Management.GetColumnCollection();
            foreach (var column in columnCollection)
            {
                int columnSpen = 1;
                System.Windows.Forms.Control control = this.GetDefaultEditControl(column);
                BuildControlArgs args = new BuildControlArgs
                {
                    Controller = this.Controller,
                    FieldName = column.Name,
                    FieldType = column.DataType,
                    Control = control,
                    ColumnSpen = columnSpen,
                    BindingSource = this.bGridControl1
                };
                if (this.Controller is ICustomBuildControl custom)
                {
                    custom.BuildControl(args);
                    // 如果取消了事件的话，则释放控件，并进行下一次的处理。
                    if (args.Cancel || args.Control is null)
                    {
                        args.Control?.Dispose();
                        continue;
                    }
                    control = args.Control;
                    columnSpen = args.ColumnSpen;
                    if (control is IBindingField bindingField)
                    {
                        bindingField.BindingField.DataSource = this.bGridControl1;
                        bindingField.BindingField.DataMember = column.Name;
                        bindingField.BindingField.Bind();
                    }
                }
                this.FIeldCollection.Add(column.Name, control);
                buildControls.Add(args);
            }
            InitializeLayoutControl(buildControls);
        }

        private void InitializeLayoutControl(List<BuildControlArgs> dic)
        {

            int rowIndex = 0; //行索引
            int columnCount = this.ColumnCount; //最大列数
            List<DevExpress.XtraLayout.BaseLayoutItem> items = new List<DevExpress.XtraLayout.BaseLayoutItem>();
            List<BuildControlArgs> tabs = new List<BuildControlArgs>();
            for (int i = 0; i < dic.Count;)
            {
                for (int columnIndex = 0; columnIndex < columnCount; columnIndex++)
                {
                    if (i >= dic.Count)
                        continue;
                    BuildControlArgs args = dic[i];
                    i++;

                    if (args.FieldType.IsClass && args.FieldType != typeof(string))
                        tabs.Add(args);
                    else if (args.FieldType == typeof(IEnumerable))
                        tabs.Add(args);
                    else
                    {
                        if (columnIndex == 0)
                        {
                            rowIndex++;
                        }
                        else if (args.BeginGroup)
                        {
                            columnIndex = 0;
                            rowIndex++;
                        }
                        int columnSpen = args.ColumnSpen;
                        columnSpen = Math.Max(1, Math.Min(columnSpen, columnCount));
                        DevExpress.XtraLayout.LayoutControlItem item = this.GetControlItem(args.Control, columnIndex, rowIndex - 1, columnSpen);
                        columnIndex += columnSpen - 1;
                        items.Add(item);
                    }
                }
                //rowIndex++;
            }
            for (int i = 0; i < rowIndex; i++)
            {
                DevExpress.XtraLayout.RowDefinition rowDefinition = new DevExpress.XtraLayout.RowDefinition();
                rowDefinition.SizeType = SizeType.AutoSize;
                this.Root.OptionsTableLayoutGroup.RowDefinitions.Add(rowDefinition);
            }

            if (tabs.Count > 0)
            {
                rowIndex++;
                DevExpress.XtraLayout.TabbedControlGroup tabbedControlGroup = new DevExpress.XtraLayout.TabbedControlGroup();
                tabbedControlGroup.Name = "tabbedControlGroup";
                tabbedControlGroup.OptionsTableLayoutItem.ColumnSpan = columnCount;
                tabbedControlGroup.OptionsTableLayoutItem.RowIndex = rowIndex;
                tabbedControlGroup.OptionsTableLayoutItem.RowSpan = 1;
                tabbedControlGroup.Padding = new DevExpress.XtraLayout.Utils.Padding(0);
                List<DevExpress.XtraLayout.LayoutControlGroup> groups = new List<DevExpress.XtraLayout.LayoutControlGroup>();
                foreach (var tab in tabs)
                {
                    this.layoutControl1.Controls.Add(tab.Control);
                    DevExpress.XtraLayout.LayoutControlItem item = new DevExpress.XtraLayout.LayoutControlItem();
                    item.Control = tab.Control;
                    item.TextVisible = false;
                    item.Location = new System.Drawing.Point(0, 0);
                    item.Padding = new DevExpress.XtraLayout.Utils.Padding(1);
                    item.Name = "layoutControlItem_" + tab.Control.Name;
                    item.Size = tab.Control.Size;
                    item.TextSize = new System.Drawing.Size(0, 0);

                    DevExpress.XtraLayout.LayoutControlGroup group = new DevExpress.XtraLayout.LayoutControlGroup();
                    group.Text = tab.FieldName;
                    group.Name = tab.FieldName;
                    group.Size = tab.Control.Size;
                    group.Items.AddRange(new DevExpress.XtraLayout.BaseLayoutItem[] { item });
                    groups.Add(group);
                }
                tabbedControlGroup.TabPages.AddRange(groups.ToArray());
                tabbedControlGroup.SelectedTabPage = groups[0];
                tabbedControlGroup.Size = new System.Drawing.Size(184, tabs.Select(x => x.Control.Height).Max());
                items.Add(tabbedControlGroup);

                DevExpress.XtraLayout.RowDefinition rowDefinition = new DevExpress.XtraLayout.RowDefinition();
                rowDefinition.SizeType = SizeType.Absolute;
                rowDefinition.Height = tabs.Select(x => x.Control.Height).Max();
                this.Root.OptionsTableLayoutGroup.RowDefinitions.Add(rowDefinition);
            }

            if (items.Count > 0)
                this.Root.Items.AddRange(items.ToArray());
        }

        /// <summary>
        /// 构建布局对象
        /// </summary>
        /// <param name="control"></param>
        /// <param name="columnIndex"></param>
        /// <param name="rowIndex"></param>
        /// <param name="columnSpen"></param>
        /// <returns></returns>
        private DevExpress.XtraLayout.LayoutControlItem GetControlItem(Control control, int columnIndex, int rowIndex, int columnSpen)
        {
            DevExpress.XtraLayout.LayoutControlItem item = new DevExpress.XtraLayout.LayoutControlItem();
            item.Control = control;
            item.TextVisible = false;
            item.OptionsTableLayoutItem.ColumnIndex = columnIndex;
            item.OptionsTableLayoutItem.RowIndex = rowIndex;
            item.OptionsTableLayoutItem.ColumnSpan = columnSpen;
            item.MinSize = new Size(control.Width, control.Height + 10);
            item.SizeConstraintsType = DevExpress.XtraLayout.SizeConstraintsType.Default;
            item.Padding = new DevExpress.XtraLayout.Utils.Padding { Top = 0, Bottom = 0, Left = 2, Right = 2 };
            item.Spacing = new DevExpress.XtraLayout.Utils.Padding { Top = 6, Bottom = 6, Left = 2, Right = 2 };
            return item;
        }


        /// <summary>
        /// 通过字段获取默认的编辑控件
        /// </summary>
        /// <param name="column"></param>
        /// <returns></returns>
        private System.Windows.Forms.Control GetDefaultEditControl(ColumnEntity column)
        {
            Control control = null;
            Type type = column.DataType;
            if (type == typeof(string) || type == typeof(char))
                control = new Marmat.Forms.TextBox();
            else if (type == typeof(DateTime))
                control = new Marmat.Forms.DateTimePicker();
            else if (type == typeof(double) || type == typeof(float) || type == typeof(decimal))
                control = new Forms.NumericBox();
            else if (type == typeof(bool))
                control = new Marmat.Forms.CheckBox() { ShowCaption = true };
            else if (type == typeof(int) || type == typeof(long))
            {
                Marmat.Forms.NumericBox numericBox = new Forms.NumericBox();
                numericBox.EditMask = "n0";
                control = numericBox;
            }
            else if (typeof(IEnumerable).IsAssignableFrom(type))
            {
                Marmat.Forms.GridControl grid = new GridControl();
                BindingField field = new BindingField(grid, nameof(grid.DataSource), this.bGridControl1, column.Name, true, DataSourceUpdateMode.OnValidation);
                field.Bind();
                control = grid;
            }
            else if (type.IsClass)
            {

            }
            else
            {
                control = new Marmat.Forms.TextBox();
            }
            control.Name = column.Name;
            if (control is IBindingField bindingField)
            {
                bindingField.BindingField.DataSource = this.bGridControl1;
                bindingField.BindingField.DataMember = column.Name;
                bindingField.BindingField.Bind();
            }
            if (control is EditControl editControl)
            {
                editControl.CaptionWidth = 120;
                editControl.ReadOnly = this.Controller.Management.AllowEdit ? BooleanEnum.Default : BooleanEnum.True;
            }

            //如果是主键的话，设为只读状态
            if (string.Equals(column.Name, this.Controller.Management.Command.PrimaryName))
            {
                if (control is EditControl editBox)
                    editBox.ReadOnly = BooleanEnum.True;
                else if (control is System.Windows.Forms.TextBox textBox)
                    textBox.ReadOnly = true;
            }
            return control;
        }

        ///// <summary>
        ///// 保存前的校验。
        ///// </summary>
        ///// <returns>校验通过，则返回true，否则返回false</returns>
        //public virtual bool OnVerify()
        //{
        //    return true;
        //}

        ///// <summary>
        ///// 保存成功后执行的函数。
        ///// </summary>
        //public virtual void OnSuccess()
        //{
        //    if (this.Controller is IDocumentEditFormNotification notification)
        //    {
        //        foreach (var item in this.FIeldCollection)
        //        {
        //            notification.RefreshControl(item.Value);
        //        }
        //    }
        //}

        /// <summary>
        /// 进入预览模式
        /// </summary>
        public virtual void Preview()
        {
            this.bGridControl1.Editable = false;
        }

        /// <summary>
        /// 进入编辑模式
        /// </summary>
        public virtual void Editor()
        {
            this.bGridControl1.Editable = true;
        }

        public bool Verify()
        {
            return true;
        }
    }
}
